#ifndef SQLPARSER_STAT_H
#define SQLPARSER_STAT_H

#include <stdlib.h>
#include <memory>
#include <vector>

namespace ment {

    struct SelectStatement;

    char* substr(const char* source, int from, int to);

    enum StatType {
	kStatLiteralFloat,
	kStatLiteralString,
	kStatLiteralInt,
	kStatLiteralNull,
	kStatStar,
	kStatParameter,
	kStatColumnRef,
	kStatFunctionRef,
	kStatOperator,
	kStatSelect,
	kStatHint,
	kStatArray,
	kStatArrayIndex,
	kStatDatetimeField,
	kStatLiteralBool,

	kStatDeleted,
	kStatUpdated
    };

    // Operator types.
    enum OperatorType {
	kOpNone,

	// 二目运算符
	kOpBetween,

	// 三元运算符
	kOpCase,
	kOpCaseListElement,  // `WHEN stat THEN stat`

	// 三元运算符
	kOpPlus,
	kOpMinus,
	kOpAsterisk,
	kOpSlash,
	kOpPercentage,
	kOpCaret,

	kOpEquals,
	kOpNotEquals,
	kOpLess,
	kOpLessEq,
	kOpGreater,
	kOpGreaterEq,
	kOpLike,
	kOpNotLike,
	kOpILike,
	kOpAnd,
	kOpOr,
	kOpIn,
	kOpConcat,

	// 一目运算符
	kOpNot,
	kOpUnaryMinus,
	kOpIsNull,
	kOpExists
    };

    enum DatetimeField {
	kDatetimeNone,
	kDatetimeSecond,
	kDatetimeMinute,
	kDatetimeHour,
	kDatetimeDay,
	kDatetimeMonth,
	kDatetimeYear,
    };

    typedef struct Stat Stat;

    // SQL元素类，可存储关键字、操作符、数据等.
    // TODO: When destructing a placeholder statession, we might need to alter the placeholder_list.
    struct Stat {
	Stat(StatType type);
	virtual ~Stat();

	StatType type;

	// TODO: Replace statessions by list.
	Stat* stat;
	Stat* stat2;
	std::vector<Stat*>* statList;
	SelectStatement* select;
	char* name;
	char* table;
	char* alias;
	double fval;
	int64_t ival;
	int64_t ival2;
	DatetimeField datetimeField;
	bool isBoolLiteral;

	OperatorType opType;
	bool distinct;

	//9.11 语法分析
	int first_line = 1;
	int first_column = 1;

	bool isType(StatType statType) const;
	bool isLiteral() const;
	bool hasAlias() const;
	bool hasTable() const;
	const char* getName() const;

	//构造函数Stat
	static Stat* make(StatType type);
	static Stat* makeOpUnary(OperatorType op, Stat* stat);
	static Stat* makeOpBinary(Stat* stat1, OperatorType op, Stat* stat2);
	static Stat* makeBetween(Stat* stat, Stat* left, Stat* right);
	static Stat* makeCaseList(Stat* caseListElement);
	static Stat* makeCaseListElement(Stat* when, Stat* then);
	static Stat* caseListAppend(Stat* caseList, Stat* caseListElement);
	static Stat* makeCase(Stat* stat, Stat* when, Stat* elseStat);
	static Stat* makeLiteral(int64_t val);
	static Stat* makeLiteral(double val);
	static Stat* makeLiteral(char* val);
	static Stat* makeLiteral(const char* val);
	static Stat* makeLiteral(bool val);
	static Stat* makeNullLiteral();
	static Stat* makeColumnRef(char* name);
	static Stat* makeColumnRef(char* table, char* name);
	static Stat* makeStar(void);
	static Stat* makeStar(char* table);
	static Stat* makeFunctionRef(char* func_name, std::vector<Stat*>* statList, bool distinct);
	static Stat* makeArray(std::vector<Stat*>* statList);
	static Stat* makeArrayIndex(Stat* stat, int64_t index);
	static Stat* makeParameter(int id);
	static Stat* makeSelect(SelectStatement* select);
	static Stat* makeExists(SelectStatement* select);
	static Stat* makeInOperator(Stat* stat, std::vector<Stat*>* statList);
	static Stat* makeInOperator(Stat* stat, SelectStatement* select);
	static Stat* makeExtract(DatetimeField datetimeField1, Stat* stat);
	static bool compare(Stat* val1, Stat* val2, OperatorType);
    };




    // Zero initializes an Stat object and assigns it to a space in the heap
    // For Hyrise we still had to put in the explicit NULL constructor
    // http://www.ex-parrot.com/~chris/random/initialise.html
    // Unused
#define ALLOC_STAT(var, type)             \
    Stat* var;                            \
    do {                                  \
        Stat zero = {type};               \
        var = (Stat*)malloc(sizeof *var); \
        *var = zero;                      \
    } while (0);
#undef ALLOC_STAT

}  // namespace ment

#endif
